﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using ZwSoft.ZwCAD.ApplicationServices;
using ZwSoft.ZwCAD.DatabaseServices;
using ZwSoft.ZwCAD.EditorInput;
using ZwSoft.ZwCAD.Geometry;
using ZwSoft.ZwCAD.GraphicsSystem;

namespace DX_Recognize.PageView
{
    public partial class GsPreviewCtrl : Panel
    {
        public GsPreviewCtrl()
        {
            InitializeComponent();
        }

        // current dwg
        public Database mCurrentDwg = null;
        // Gs specific
        public ZwSoft.ZwCAD.GraphicsSystem.Manager mpManager = null;
        public ZwSoft.ZwCAD.GraphicsSystem.Device mpDevice = null;
        public ZwSoft.ZwCAD.GraphicsSystem.Model mpModel = null;
        public ZwSoft.ZwCAD.GraphicsSystem.View mpView = null;
        // flags
        public bool mZooming = false;
        public bool mMouseDown = false;
        public bool mMouseMoving = false;
        public bool mbPanning = false;
        public System.Drawing.Point mStartPoint;
        public System.Drawing.Point mEndPoint;

        // called from InitDrawingControl, does GsPreviewCtrl specific initialization
        public void Init(Document doc, Database db)
        {
            mCurrentDwg = db;
            Database dd = this.mCurrentDwg;
            // check to see if the manager is already initalised
            if (null == mpManager)
            {
                // if not let's set it up
                mpManager = doc.GraphicsManager;
                // here's some test code to show the GS Events working
                mpManager.ViewToBeDestroyed += new ViewToBeDestroyedEventHandler(GSUtil.mpManager_ViewToBeDestroyed);
                mpManager.ViewWasCreated += new ViewWasCreatedEventHandler(GSUtil.mpManager_ViewWasCreated);
                mpManager.GsToBeUnloaded += new GsToBeUnloadedEventHandler(GSUtil.mpManager_GsToBeUnloaded);
                mpManager.ConfigWasModified += new ConfigWasModifiedEventHandler(GSUtil.mpManager_ConfigWasModified);

                // now create the Gs control, create the autocad device passing the handle to the Windows panel
#if ZRX_2021
                GraphicsKernel graphicsKernel = new GraphicsKernel();
                mpDevice = mpManager.CreateZWCADDevice(graphicsKernel, this.Handle);
#else
        mpDevice = mpManager.CreateZWCADDevice(this.Handle);
#endif

                // resize the device to the panel size
                mpDevice.OnSize(this.Size);
                // now create a new gs view
                mpView = new ZwSoft.ZwCAD.GraphicsSystem.View();
                // and create the model
#if ZRX_2021
                mpModel = mpManager.CreateZWCADModel(graphicsKernel);
#else
        mpModel = mpManager.CreateZWCADModel();
#endif
                // add the view to the device
                mpDevice.Add(mpView);
            }
        }

        public void ClearAll()
        {
            if (mpDevice != null)
            {
                bool b = mpDevice.Erase(mpView);
            }
            if (mpView != null)
            {
                mpView.EraseAll();
                mpView.Dispose();
                mpView = null;
            }
            if (mpManager != null)
            {
                if (mpModel != null)
                {
                    mpModel.Dispose();
                    mpModel = null;
                }

                if (mpDevice != null)
                {
                    mpDevice.Dispose();
                    mpDevice = null;
                }
                mpManager = null;
            }
        }
        public void ErasePreview()
        {
            if (mpView != null)
                mpView.EraseAll();
            if (mpManager != null && mpModel != null)
            {
                mpModel.Dispose();
                mpModel = null;
            }
        }

        // draws the zoom window rectangle
        public void RubberRectangle(System.Drawing.Point startPt, System.Drawing.Point endPt)
        {
            // create a new instance of my GDI helper class, it seems too tricky to create simple XOR graphics
            // in .NET so let's resort to direct calls instead
            GSUtil.RubberbandRectangle rect = new GSUtil.RubberbandRectangle();
            System.Drawing.Graphics graphics = this.CreateGraphics();
            // draw the XOR rectangle 
            rect.DrawXORRectangle(graphics, startPt, endPt);
        }
        public void refreshView()
        {
            mpView.Invalidate();
            mpView.Update();
        }
        protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
        {
            base.OnPaint(e);
            refreshView();
        }

        protected override void OnMouseMove(System.Windows.Forms.MouseEventArgs e)
        {
            base.OnMouseMove(e);
            if (mpView != null)
            {
                if (mZooming)
                {
                    // if left button is down
                    if (mMouseDown)
                    {
                        if (mMouseMoving)
                        {
                            // erase the old rectangle
                            RubberRectangle(mStartPoint, mEndPoint);
                        }
                        // draw the new rectangle
                        RubberRectangle(mStartPoint, e.Location);
                        mMouseMoving = true;
                        // save the new point for next time
                        mEndPoint = e.Location;
                    }
                }
                else
                {
                    if (mbPanning)
                    {
                        //transform the point from device coordinates to
                        //world coordinates
                        Vector3d pan_vec = new Vector3d(-(e.Location.X - mStartPoint.X), e.Location.Y - mStartPoint.Y, 0);
                        pan_vec.TransformBy(mpView.ViewingMatrix * mpView.WorldToDeviceMatrix.Inverse());
                        mpView.Dolly(pan_vec);
                        refreshView();
                        mStartPoint = e.Location;
                    }
                   
                }
            }
        }

        protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e)
        {
            base.OnMouseDown(e);
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                // if zooming
                if (mZooming)
                {
                    mMouseDown = true;
                    mMouseMoving = false;
                }
                else
                    this.Focus();

            }
            else if (e.Button == System.Windows.Forms.MouseButtons.Middle)
                mbPanning = true;
            mStartPoint = e.Location;
        }
        protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs e)
        {
            base.OnMouseUp(e);
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                if (mZooming && mMouseDown)
                {
                    // end zoom
                    mZooming = false;
                    mMouseDown = false;
                    mMouseMoving = false;
                    mpView.ZoomWindow(new Point2d(mStartPoint.X, this.Bottom - mStartPoint.Y), new Point2d(mEndPoint.X, this.Bottom - mEndPoint.Y));
                    refreshView();
                }
            }
            else if (e.Button == System.Windows.Forms.MouseButtons.Middle)
                mbPanning = false;
        }
        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            if (mpDevice != null)
                mpDevice.OnSize(this.Size);
        }
    }

    public class GSUtil
    {
        public const String strActive = "*Active";
        public const String strActiveSettings = "ACAD_RENDER_ACTIVE_SETTINGS";
        public static void CustomUpdate(System.IntPtr parmeter, int left, int right, int bottom, int top)
        {
            MessageBox.Show("Left:" + left + "Right" + right + "Bottom" + bottom + "Top" + top);
        }

        public static bool GetActiveViewPortInfo(ref double height, ref double width, ref Point3d target, ref Vector3d viewDir, ref double viewTwist, bool getViewCenter)
        {
            // get the editor object
            Editor ed = ZwSoft.ZwCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;
            ed.UpdateTiledViewportsInDatabase();
            Database db = HostApplicationServices.WorkingDatabase;
            using (Transaction t = db.TransactionManager.StartTransaction())
            {
                ViewportTable vt = (ViewportTable)t.GetObject(db.ViewportTableId, OpenMode.ForRead);
                ViewportTableRecord btr = (ViewportTableRecord)t.GetObject(vt[GSUtil.strActive], OpenMode.ForRead);
                height = btr.Height;
                width = btr.Width;
                target = btr.Target;
                viewDir = btr.ViewDirection;
                viewTwist = btr.ViewTwist;
                t.Commit();
            }
            return true;
        }
        public static void mpManager_ViewToBeDestroyed(Object sender, ViewEventArgs e)
        {
            // get the editor object
            Editor ed = ZwSoft.ZwCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;
            ed.WriteMessage("BlockView: Event ViewToBeDestroyed fired");
        }
        public static void mpManager_ViewWasCreated(Object sender, ViewEventArgs e)
        {
            // get the editor object
            Editor ed = ZwSoft.ZwCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;
            ed.WriteMessage("BlockView: Event ViewWasCreated fired");
        }
        public static void mpManager_GsToBeUnloaded(Object sender, EventArgs e)
        {
            // get the editor object
            Editor ed = ZwSoft.ZwCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;
            ed.WriteMessage("BlockView: Event GsToBeUnloaded fired");
        }
        public static void mpManager_ConfigWasModified(Object sender, EventArgs e)
        {
            // get the editor object
            Editor ed = ZwSoft.ZwCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;
            ed.WriteMessage("BlockView: Event ConfigWasModified fired");
        }

        public class RubberbandRectangle
        {
            public enum PenStyles
            {
                PS_SOLID = 0,
                PS_DASH = 1,
                PS_DOT = 2,
                PS_DASHDOT = 3,
                PS_DASHDOTDOT = 4
            }
            // These values come from the larger set of defines in WinGDI.h,
            // but are all that are needed for this application.  If this class
            // is expanded for more generic rectangle drawing, they should be
            // replaced by enums from those sets of defones.
            private int NULL_BRUSH = 5;
            private int R2_XORPEN = 7;
            private PenStyles penStyle;
            private int BLACK_PEN = 0;

            // Default contructor - sets member fields
            public RubberbandRectangle()
            {
                penStyle = PenStyles.PS_DOT;
            }

            // penStyles property get/set.
            public PenStyles PenStyle
            {
                get { return penStyle; }
                set { penStyle = value; }
            }

            public void DrawXORRectangle(Graphics grp, System.Drawing.Point startPt, System.Drawing.Point endPt)
            {
                int X1 = startPt.X;
                int Y1 = startPt.Y;
                int X2 = endPt.X;
                int Y2 = endPt.Y;
                // Extract the Win32 HDC from the Graphics object supplied.
                IntPtr hdc = grp.GetHdc();

                // Create a pen with a dotted style to draw the border of the
                // rectangle.
                IntPtr gdiPen = CreatePen(penStyle,
                              1, BLACK_PEN);

                // Set the ROP cdrawint mode to XOR.
                SetROP2(hdc, R2_XORPEN);

                // Select the pen into the device context.
                IntPtr oldPen = SelectObject(hdc, gdiPen);

                // Create a stock NULL_BRUSH brush and select it into the device
                // context so that the rectangle isn't filled.
                IntPtr oldBrush = SelectObject(hdc,
                                     GetStockObject(NULL_BRUSH));

                // Now XOR the hollow rectangle on the Graphics object with
                // a dotted outline.
                Rectangle(hdc, X1, Y1, X2, Y2);

                // Put the old stuff back where it was.
                SelectObject(hdc, oldBrush); // no need to delete a stock object
                SelectObject(hdc, oldPen);
                DeleteObject(gdiPen);       // but we do need to delete the pen

                // Return the device context to Windows.
                grp.ReleaseHdc(hdc);
            }

            // Use Interop to call the corresponding Win32 GDI functions
            [System.Runtime.InteropServices.DllImportAttribute("gdi32.dll")]
            private static extern int SetROP2(
                    IntPtr hdc,     // Handle to a Win32 device context
                    int enDrawMode  // Drawing mode
                    );
            [System.Runtime.InteropServices.DllImportAttribute("gdi32.dll")]
            private static extern IntPtr CreatePen(
                    PenStyles enPenStyle,   // Pen style from enum PenStyles
                    int nWidth,             // Width of pen
                    int crColor             // Color of pen
                    );
            [System.Runtime.InteropServices.DllImportAttribute("gdi32.dll")]
            private static extern bool DeleteObject(
                    IntPtr hObject  // Win32 GDI handle to object to delete
                    );
            [System.Runtime.InteropServices.DllImportAttribute("gdi32.dll")]
            private static extern IntPtr SelectObject(
                    IntPtr hdc,     // Win32 GDI device context
                    IntPtr hObject  // Win32 GDI handle to object to select
                    );
            [System.Runtime.InteropServices.DllImportAttribute("gdi32.dll")]
            private static extern void Rectangle(
                    IntPtr hdc,         // Handle to a Win32 device context
                    int X1,             // x-coordinate of top left corner
                    int Y1,             // y-cordinate of top left corner
                    int X2,             // x-coordinate of bottom right corner
                    int Y2              // y-coordinate of bottm right corner
                    );
            [System.Runtime.InteropServices.DllImportAttribute("gdi32.dll")]
            private static extern IntPtr GetStockObject(
                    int brStyle // Selected from the WinGDI.h BrushStyles enum
                    );

            // C# version of Win32 RGB macro
            private static int RGB(int R, int G, int B)
            {
                return (R | (G << 8) | (B << 16));
            }
        }
    }
}
